package com.nl.lib_project.view.radar

import android.annotation.SuppressLint
import android.content.Context
import android.graphics.*
import android.text.TextPaint
import android.text.TextUtils
import android.util.AttributeSet
import android.view.GestureDetector
import android.view.GestureDetector.SimpleOnGestureListener
import android.view.MotionEvent
import android.view.View
import android.widget.Scroller
import com.nl.lib_project.R
import java.util.*
import kotlin.math.*

/** @author changhai qiu Email:qstumn@163.com */
class RadarView
@JvmOverloads
constructor(private val mContext: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0) :
    View(mContext, attrs, defStyleAttr) {
  private var mWebMode = 0
  private var mPerimeter = 0.0
  private var mRadius = 0f
  private var mPointCenter: PointF? = null
  private var mLayerLineColor = 0
  private var mLayerLineWidth = 0f
  private var mVertexLineColor = 0
  private var mVertexLineWidth = 0f
  private var mLayer = 0
  private var mLayerColor: ArrayList<Int>? = null
  private var mMaxValue = 0f
  private var mMaxValues: ArrayList<Float>? = null
  private var mVertexText: ArrayList<String>? = null
  private var mVertexIcon: ArrayList<Bitmap>? = null
  private var mVertexIconPosition = 0
  private var mVertexIconSize = 0f
  private var mVertexIconMargin = 0f
  private var mVertexTextColor = 0
  private var mVertexTextSize = 0f
  private var mVertexTextOffset = 0f
  private var mMaxVertex = 0
  private var mCenterTextSize = 0f
  private var mCenterTextColor = 0
  private var mAngle = 0.0
  private var mRotateAngle = 0.0
  private var mRadarData: ArrayList<RadarData>? = null
  private var mVertexIconRect: RectF? = null
  private var mRadarLinePaint: Paint? = null
  private var mLayerPaint: Paint? = null
  private var mVertexTextPaint: TextPaint? = null
  private var mValuePaint: Paint? = null
  private var mValueTextPaint: TextPaint? = null
  private var mRadarPath: Path? = null
  private var mCenterTextPaint: TextPaint? = null
  private var mDetector: GestureDetector? = null
  private var mScroller: Scroller? = null
  private var mFlingPoint = 0f
  private var mRotateOrientation = 0.0
  private var isRotationEnable = false
  private var mEmptyHint = "no data"
  private var mMaxLengthVertexText: String? = null
  private var mCenterText: String? = null
  private var mAnimeUtil: AnimeUtil? = null
  private fun initAttrs(attrs: AttributeSet?) {
    val typedArray = mContext.obtainStyledAttributes(attrs, R.styleable.RadarView)
    mLayer = typedArray.getInt(R.styleable.RadarView_radar_layer, 5)
    isRotationEnable = typedArray.getBoolean(R.styleable.RadarView_rotation_enable, true)
    mWebMode = typedArray.getInt(R.styleable.RadarView_web_mode, WEB_MODE_POLYGON)
    mMaxValue = typedArray.getFloat(R.styleable.RadarView_max_value, 0f)
    mLayerLineColor = typedArray.getColor(R.styleable.RadarView_layer_line_color, -0x616162)
    mLayerLineWidth = typedArray.getDimension(R.styleable.RadarView_layer_line_width, dp2px(1f))
    mVertexLineColor = typedArray.getColor(R.styleable.RadarView_vertex_line_color, -0x616162)
    mVertexLineWidth = typedArray.getDimension(R.styleable.RadarView_vertex_line_width, dp2px(1f))
    mVertexTextColor =
        typedArray.getColor(R.styleable.RadarView_vertex_text_color, mVertexLineColor)
    mVertexTextSize = typedArray.getDimension(R.styleable.RadarView_vertex_text_size, dp2px(12f))
    mVertexTextOffset = typedArray.getDimension(R.styleable.RadarView_vertex_text_offset, 0f)
    mCenterTextColor =
        typedArray.getColor(R.styleable.RadarView_center_text_color, mVertexLineColor)
    mCenterTextSize = typedArray.getDimension(R.styleable.RadarView_center_text_size, dp2px(30f))
    mCenterText = typedArray.getString(R.styleable.RadarView_center_text)
    mVertexIconSize = typedArray.getDimension(R.styleable.RadarView_vertex_icon_size, dp2px(20f))
    mVertexIconPosition =
        typedArray.getInt(R.styleable.RadarView_vertex_icon_position, VERTEX_ICON_POSITION_TOP)
    mVertexIconMargin = typedArray.getDimension(R.styleable.RadarView_vertex_icon_margin, 0f)
    val vertexTextResid = typedArray.getResourceId(R.styleable.RadarView_vertex_text, 0)
    typedArray.recycle()
    initVertexText(vertexTextResid)
  }

  private fun initVertexText(vertexTextResid: Int) {
    try {
      val stringArray = mContext.resources.getStringArray(vertexTextResid)
      if (stringArray.isNotEmpty()) {
        mVertexText = ArrayList()
        mVertexText?.addAll(stringArray)
      }
    } catch (e: Exception) {}
  }

  private fun init() {
    mRadarPath = Path()
    mAnimeUtil = AnimeUtil(this)
    mScroller = Scroller(mContext)
    mDetector = GestureDetector(mContext, GestureListener())
    mDetector!!.setIsLongpressEnabled(false)
    mRadarData = ArrayList()
    mLayerColor = ArrayList()
    initLayerColor()
    mRadarLinePaint = Paint()
    mLayerPaint = Paint()
    mValuePaint = Paint()
    mVertexTextPaint = TextPaint()
    mValueTextPaint = TextPaint()
    mCenterTextPaint = TextPaint()
    mRadarLinePaint!!.isAntiAlias = true
    mLayerPaint!!.isAntiAlias = true
    mVertexTextPaint!!.isAntiAlias = true
    mCenterTextPaint!!.isAntiAlias = true
    mValueTextPaint!!.isAntiAlias = true
    mValuePaint!!.isAntiAlias = true
    mValueTextPaint!!.isFakeBoldText = true
    mVertexIconRect = RectF()
  }

  private fun initLayerColor() {
    if (mLayerColor == null) {
      mLayerColor = ArrayList()
    }
    if (mLayerColor!!.size < mLayer) {
      val size = mLayer - mLayerColor!!.size
      for (i in 0 until size) {
        mLayerColor!!.add(Color.TRANSPARENT)
      }
    }
  }

  var webMode: Int
    get() = mWebMode
    set(webMode) {
      check(!(webMode != WEB_MODE_POLYGON && webMode != WEB_MODE_CIRCLE)) {
        "only support WEB_MODE_POLYGON or WEB_MODE_CIRCLE"
      }
      mWebMode = webMode
      invalidate()
    }
  var layer: Int
    get() = mLayer
    set(layer) {
      mLayer = layer
      initLayerColor()
      invalidate()
    }
  val layerColor: List<Int>?
    get() = mLayerColor

  fun setLayerColor(layerColor: ArrayList<Int>?) {
    mLayerColor = layerColor
    initLayerColor()
    invalidate()
  }

  val vertexIcon: List<Bitmap>?
    get() = mVertexIcon

  fun setVertexIconBitmap(vertexIconBitmap: ArrayList<Bitmap>?) {
    mVertexIcon = vertexIconBitmap
    invalidate()
  }

  fun setVertexIconResid(vertexIconResid: List<Int?>) {
    mVertexIcon = ArrayList()
    for (integer in vertexIconResid) {
      mVertexIcon!!.add(BitmapFactory.decodeResource(mContext.resources, integer!!))
    }
    invalidate()
  }

  /**
   * @param vertexIconPosition only support [RadarView.VERTEX_ICON_POSITION_BOTTOM]
   * [RadarView.VERTEX_ICON_POSITION_CENTER] [RadarView.VERTEX_ICON_POSITION_LEFT]
   * [RadarView.VERTEX_ICON_POSITION_RIGHT] [RadarView.VERTEX_ICON_POSITION_TOP]
   */
  var vertexIconPosition: Int
    get() = mVertexIconPosition
    set(vertexIconPosition) {
      check(
          !(vertexIconPosition != VERTEX_ICON_POSITION_BOTTOM &&
              vertexIconPosition != VERTEX_ICON_POSITION_CENTER &&
              vertexIconPosition != VERTEX_ICON_POSITION_LEFT &&
              vertexIconPosition != VERTEX_ICON_POSITION_RIGHT &&
              vertexIconPosition != VERTEX_ICON_POSITION_TOP)) {
        "only support VERTEX_ICON_POSITION_BOTTOM" +
            "  VERTEX_ICON_POSITION_CENTER  VERTEX_ICON_POSITION_LEFT " +
            " VERTEX_ICON_POSITION_RIGHT  VERTEX_ICON_POSITION_TOP"
      }
      mVertexIconPosition = vertexIconPosition
      invalidate()
    }
  var vertexIconSize: Float
    get() = mVertexIconSize
    set(vertexIconSize) {
      mVertexIconSize = vertexIconSize
      invalidate()
    }
  var vertexIconMargin: Float
    get() = mVertexIconMargin
    set(margin) {
      mVertexIconMargin = margin
      invalidate()
    }
  var vertexTextOffset: Float
    get() = mVertexTextOffset
    set(vertexOffset) {
      mVertexTextOffset = vertexOffset
      invalidate()
    }
  var maxValue: Float
    get() = mMaxValue
    set(maxValue) {
      mMaxValue = maxValue
      mMaxValues = null
      invalidate()
    }
  val maxValues: List<Float>?
    get() = mMaxValues

  fun setMaxValues(maxValues: ArrayList<Float>?) {
    mMaxValues = maxValues
    initMaxValues()
    invalidate()
  }

  private fun initMaxValues() {
    if (mMaxValues != null && mMaxValues!!.size < mMaxVertex) {
      val size = mMaxVertex - mMaxValues!!.size
      for (i in 0 until size) {
        mMaxValues!!.add(0f)
      }
    }
  }

  val vertexText: List<String>?
    get() = mVertexText

  fun setVertexText(vertexText: ArrayList<String>?) {
    mVertexText = vertexText
    initVertexText()
    invalidate()
  }

  var vertexTextColor: Int
    get() = mVertexTextColor
    set(vertexTextColor) {
      mVertexTextColor = vertexTextColor
      invalidate()
    }
  var vertexTextSize: Float
    get() = mVertexTextSize
    set(vertexTextSize) {
      mVertexTextSize = vertexTextSize
      invalidate()
    }
  var centerText: String?
    get() = mCenterText
    set(text) {
      mCenterText = text
      invalidate()
    }
  var centerTextSize: Float
    get() = mCenterTextSize
    set(centerTextSize) {
      mCenterTextSize = centerTextSize
      invalidate()
    }
  var centerTextColor: Int
    get() = mCenterTextColor
    set(centerTextColor) {
      mCenterTextColor = centerTextColor
      invalidate()
    }
  val layerLineColor: Int
    get() = mLayerLineColor

  @JvmName("getLayerLineColor1")
  fun getLayerLineColor(): Int {
    return mLayerLineColor
  }

  @JvmName("setLayerLineColor1")
  fun setLayerLineColor(color: Int) {
    mLayerLineColor = color
    invalidate()
  }

  fun getLayerLineWidth(): Float {
    return mLayerLineWidth
  }

  fun setLayerLineWidth(width: Float) {
    mLayerLineWidth = width
    invalidate()
  }

  fun getVertexLineColor(): Int {
    return mVertexLineColor
  }

  fun setVertexLineColor(color: Int) {
    mVertexLineColor = color
    invalidate()
  }

  fun getVertexLineWidth(): Float {
    return mVertexLineWidth
  }

  fun setVertexLineWidth(width: Float) {
    mVertexLineWidth = width
    invalidate()
  }

  fun animeValue(duration: Int) {
    for (radarData in mRadarData!!) {
      animeValue(duration, radarData)
    }
  }

  fun animeValue(duration: Int, data: RadarData) {
    // 去除加载时的动画
    //    if (!mAnimeUtil!!.isPlaying(data)) {
    //      mAnimeUtil!!.animeValue(AnimeUtil.AnimeType.ZOOM, duration, data)
    //    }
  }

  fun addData(data: RadarData) {
    mRadarData!!.add(data)
    initData(data)
    animeValue(2000, data)
  }

  fun setEmptyHint(hint: String) {
    mEmptyHint = hint
    invalidate()
  }

  fun getEmptyHint(): String {
    return mEmptyHint
  }

  fun removeRadarData(data: RadarData) {
    mRadarData!!.remove(data)
    invalidate()
  }

  fun clearRadarData() {
    mRadarData!!.clear()
    invalidate()
  }

  private fun initData(data: RadarData) {
    if (data.value.isEmpty()) return
    val value = data.value
    val max = Collections.max(value)
    if (mMaxValue == 0f || mMaxValue < max) {
      mMaxValue = max
    }
    val valueSize = value.size
    if (mMaxVertex < valueSize) {
      mMaxVertex = valueSize
    }
    mAngle = 2 * PI / mMaxVertex
    initVertexText()
    initMaxValues()
  }

  private fun initVertexText() {
    if (mVertexText == null || mVertexText!!.size == 0) {
      mVertexText = ArrayList()
      for (i in 0 until mMaxVertex) {
        val text = ('A'.code + i).toChar()
        mVertexText!!.add(text.toString())
      }
    } else if (mVertexText!!.size < mMaxVertex) {
      val size = mMaxVertex - mVertexText!!.size
      for (i in 0 until size) {
        mVertexText!!.add("")
      }
    }
    if (mVertexText!!.size == 0) {
      return
    }
    mMaxLengthVertexText =
        Collections.max(mVertexText) { lhs: String, rhs: String -> lhs.length - rhs.length }
  }

  override fun onDraw(canvas: Canvas) {
    if (mRadarData!!.size == 0) {
      mValueTextPaint!!.textSize = dp2px(16f)
      val hintWidth = mValueTextPaint!!.measureText(mEmptyHint)
      canvas.drawText(
          mEmptyHint, mPointCenter!!.x - hintWidth / 2, mPointCenter!!.y, mValueTextPaint!!)
    } else {
      initPaint()
      calcRadius()
      drawRadar(canvas)
      drawData(canvas)
      drawCenterText(canvas)
    }
  }

  private fun initPaint() {
    mRadarLinePaint!!.style = Paint.Style.STROKE
    mVertexTextPaint!!.color = mVertexTextColor
    mVertexTextPaint!!.textSize = mVertexTextSize
    mLayerPaint!!.style = Paint.Style.FILL
    mCenterTextPaint!!.textSize = mCenterTextSize
    mCenterTextPaint!!.color = mCenterTextColor
  }

  private fun drawRadar(canvas: Canvas) {
    if (mWebMode == WEB_MODE_POLYGON) {
      drawWeb(canvas)
    } else if (mWebMode == WEB_MODE_CIRCLE) {
      drawCircle(canvas)
    }
    drawRadarLine(canvas)
  }

  private fun drawWeb(canvas: Canvas) {
    for (i in mLayer downTo 1) {
      val radius = mRadius / mLayer * i
      val layerColor = mLayerColor!![i - 1]
      mRadarPath!!.reset()
      for (j in 1..mMaxVertex) {
        val angleSin = sin(mAngle * j - mRotateAngle)
        val angleCos = cos(mAngle * j - mRotateAngle)
        val x = (mPointCenter!!.x + angleSin * radius).toFloat()
        val y = (mPointCenter!!.y - angleCos * radius).toFloat()
        if (j == 1) {
          mRadarPath!!.moveTo(x, y)
        } else {
          mRadarPath!!.lineTo(x, y)
        }
      }
      mRadarPath!!.close()
      if (layerColor != Color.TRANSPARENT) {
        mLayerPaint!!.color = layerColor
        canvas.drawPath(mRadarPath!!, mLayerPaint!!)
      }
      if (mLayerLineWidth > 0) {
        mRadarLinePaint!!.color = mLayerLineColor
        mRadarLinePaint!!.strokeWidth = mLayerLineWidth
        canvas.drawPath(mRadarPath!!, mRadarLinePaint!!)
      }
    }
  }

  private fun drawCircle(canvas: Canvas) {
    for (i in mLayer downTo 1) {
      val radius = mRadius / mLayer * i
      val layerColor = mLayerColor!![i - 1]
      if (layerColor != Color.TRANSPARENT) {
        mLayerPaint!!.color = layerColor
        canvas.drawCircle(mPointCenter!!.x, mPointCenter!!.y, radius, mLayerPaint!!)
      }
      if (mLayerLineWidth > 0) {
        mRadarLinePaint!!.color = mLayerLineColor
        mRadarLinePaint!!.strokeWidth = mLayerLineWidth
        canvas.drawCircle(mPointCenter!!.x, mPointCenter!!.y, radius, mRadarLinePaint!!)
      }
    }
  }

  private fun drawRadarLine(canvas: Canvas) {
    for (i in 1..mMaxVertex) {
      val angleSin = sin(mAngle * i - mRotateAngle)
      val angleCos = cos(mAngle * i - mRotateAngle)
      drawVertex(canvas, i, angleSin, angleCos)
      drawVertexLine(canvas, angleSin, angleCos)
    }
  }

  private fun drawVertex(canvas: Canvas, index: Int, angleSin: Double, angleCos: Double) {
    val x = (mPointCenter!!.x + angleSin * (mRadius + mVertexTextOffset)).toFloat()
    val y = (mPointCenter!!.y - angleCos * (mRadius + mVertexTextOffset)).toFloat()
    val text = mVertexText!![index - 1]
    val textWidth = mVertexTextPaint!!.measureText(text)
    val fontMetrics = mVertexTextPaint!!.fontMetrics
    val textHeight = fontMetrics.descent - fontMetrics.ascent
    if (mVertexIcon != null && mVertexIcon!!.size >= index) {
      val icon = mVertexIcon!![index - 1]
      val iconSize = RotateUtil.geometricScaling(icon.width, icon.height, mVertexIconSize)
      var textY = y + textHeight / 4
      var textX = x - textWidth / 2
      when (mVertexIconPosition) {
        VERTEX_ICON_POSITION_LEFT -> {
          mVertexIconRect!!.left = x - (iconSize[0] + mVertexIconMargin + textWidth) / 2f
          mVertexIconRect!!.right = mVertexIconRect!!.left + iconSize[0]
          mVertexIconRect!!.top = y - iconSize[1] / 2f
          mVertexIconRect!!.bottom = mVertexIconRect!!.top + iconSize[1]
          textX = mVertexIconRect!!.right + mVertexIconMargin
        }
        VERTEX_ICON_POSITION_RIGHT -> {
          mVertexIconRect!!.right = x + (iconSize[0] + mVertexIconMargin + textWidth) / 2f
          mVertexIconRect!!.left = mVertexIconRect!!.right - iconSize[0]
          mVertexIconRect!!.top = y - iconSize[1] / 2f
          mVertexIconRect!!.bottom = mVertexIconRect!!.top + iconSize[1]
          textX = mVertexIconRect!!.left - mVertexIconMargin - textWidth
        }
        VERTEX_ICON_POSITION_TOP -> {
          mVertexIconRect!!.left = x - iconSize[0] / 2f
          mVertexIconRect!!.right = mVertexIconRect!!.left + iconSize[0]
          mVertexIconRect!!.top = y - (iconSize[1] + mVertexIconMargin + textHeight) / 2f
          mVertexIconRect!!.bottom = mVertexIconRect!!.top + iconSize[1]
          textY = mVertexIconRect!!.bottom + mVertexIconMargin + textHeight / 2f + textHeight / 4f
        }
        VERTEX_ICON_POSITION_BOTTOM -> {
          mVertexIconRect!!.left = x - iconSize[0] / 2f
          mVertexIconRect!!.right = mVertexIconRect!!.left + iconSize[0]
          mVertexIconRect!!.bottom = y + (iconSize[1] + mVertexIconMargin + textHeight) / 2f
          mVertexIconRect!!.top = mVertexIconRect!!.bottom - iconSize[1]
          textY = mVertexIconRect!!.top - mVertexIconMargin - textHeight / 2f + textHeight / 4f
        }
        VERTEX_ICON_POSITION_CENTER -> {
          mVertexIconRect!!.left = x - iconSize[0] / 2f
          mVertexIconRect!!.right = mVertexIconRect!!.left + iconSize[0]
          mVertexIconRect!!.top = y - iconSize[1] / 2f
          mVertexIconRect!!.bottom = mVertexIconRect!!.top + iconSize[1]
        }
      }
      drawVertexImpl(canvas, text, icon, mVertexTextPaint, textY, textX)
    } else {
      drawVertexImpl(canvas, text, null, mVertexTextPaint, x - textWidth / 2, y + textHeight / 4)
    }
  }

  private fun drawVertexImpl(
      canvas: Canvas,
      text: String?,
      icon: Bitmap?,
      paint: Paint?,
      textY: Float,
      textX: Float
  ) {
    if (icon != null) {
      canvas.drawBitmap(icon, null, mVertexIconRect!!, paint)
    }
    if (!TextUtils.isEmpty(text)) {
      canvas.drawText(text!!, textX, textY, paint!!)
    }
  }

  private fun drawVertexLine(canvas: Canvas, angleSin: Double, angleCos: Double) {
    if (mVertexLineWidth <= 0) {
      return
    }
    val x = (mPointCenter!!.x + angleSin * mRadius).toFloat()
    val y = (mPointCenter!!.y - angleCos * mRadius).toFloat()
    mRadarLinePaint!!.color = mVertexLineColor
    mRadarLinePaint!!.strokeWidth = mVertexLineWidth
    canvas.drawLine(mPointCenter!!.x, mPointCenter!!.y, x, y, mRadarLinePaint!!)
  }

  private fun drawData(canvas: Canvas) {
    for (i in mRadarData!!.indices) {
      val radarData = mRadarData!![i]
      mValuePaint!!.color = radarData.color
      mValueTextPaint!!.textSize = radarData.valueTextSize
      mValueTextPaint!!.color = radarData.valueTextColor
      val values = radarData.value
      mRadarPath!!.reset()
      val textPoint = arrayOfNulls<PointF>(mMaxVertex)
      for (j in 1..mMaxVertex) {
        var value = 0f
        if (values.size >= j) {
          value = values[j - 1]
        }
        var percent: Float
        percent =
            if (mMaxValues != null) {
              value / mMaxValues!![j - 1]
            } else {
              value / mMaxValue
            }
        if (percent.isInfinite()) {
          percent = 1f
        } else if (percent.isNaN()) {
          percent = 0f
        }
        if (percent > 1f) {
          percent = 1f
        }
        // 如果雷达图中某个表情值小于0.8则将展示的最大值为0.8
        if (value < 0.8f) {
          percent *= 0.8f
        }

        val x =
            (mPointCenter!!.x +
                    sin(mAngle * j - mRotateAngle) * (mRadius - mLayerLineWidth) * percent)
                .toFloat()
        val y =
            (mPointCenter!!.y -
                    cos(mAngle * j - mRotateAngle) * (mRadius - mLayerLineWidth) * percent)
                .toFloat()

        if (j == 1) {
          mRadarPath!!.moveTo(x, y)
        } else {
          mRadarPath!!.lineTo(x, y)
        }
        textPoint[j - 1] = PointF(x, y)
      }
      mRadarPath!!.close()
      mValuePaint!!.alpha = 255
      mValuePaint!!.style = Paint.Style.STROKE
      mValuePaint!!.strokeWidth = radarData.lineWidth
      canvas.drawPath(mRadarPath!!, mValuePaint!!)
      if (radarData.isFillRadarColor) {
        mValuePaint!!.style = Paint.Style.FILL
        mValuePaint!!.alpha = 150
        canvas.drawPath(mRadarPath!!, mValuePaint!!)
      }
      if (radarData.isValueTextEnable) {
        val valueText = radarData.valueText
        for (k in textPoint.indices) {
          var text: String? = ""
          if (valueText!!.size > k) {
            text = valueText[k]
          }
          val textWidth = mValueTextPaint!!.measureText(text)
          val fontMetrics = mValueTextPaint!!.fontMetrics
          val textHeight = fontMetrics.descent - fontMetrics.ascent
          canvas.drawText(
              text!!,
              textPoint[k]!!.x - textWidth / 2,
              textPoint[k]!!.y + textHeight / 3,
              mValueTextPaint!!)
        }
      }
    }
  }

  private fun drawCenterText(canvas: Canvas) {
    if (!TextUtils.isEmpty(mCenterText)) {
      val textWidth = mCenterTextPaint!!.measureText(mCenterText)
      val fontMetrics = mCenterTextPaint!!.fontMetrics
      val textHeight = fontMetrics.descent - fontMetrics.ascent
      canvas.drawText(
          mCenterText!!,
          mPointCenter!!.x - textWidth / 2,
          mPointCenter!!.y + textHeight / 3,
          mCenterTextPaint!!)
    }
  }

  private fun calcRadius() {
    if (mVertexText == null || mVertexText!!.size == 0) {
      mRadius = mPointCenter!!.x.coerceAtMost(mPointCenter!!.y) - mVertexTextOffset
    } else {
      val maxWidth: Float =
          if (mVertexIconPosition == VERTEX_ICON_POSITION_LEFT ||
              mVertexIconPosition == VERTEX_ICON_POSITION_RIGHT) {
            (mVertexTextPaint!!.measureText(mMaxLengthVertexText) +
                mVertexIconMargin +
                mVertexIconSize) / 2
          } else {
            mVertexTextPaint!!.measureText(mMaxLengthVertexText).coerceAtLeast(mVertexIconSize) / 2
          }
      mRadius = mPointCenter!!.x.coerceAtMost(mPointCenter!!.y) - (maxWidth + mVertexTextOffset)
      mPerimeter = 2 * PI * mRadius
    }
  }

  @SuppressLint("ClickableViewAccessibility")
  override fun onTouchEvent(event: MotionEvent): Boolean {
    when (event.action) {
      MotionEvent.ACTION_DOWN -> parent.requestDisallowInterceptTouchEvent(isRotationEnable)
      MotionEvent.ACTION_UP -> parent.requestDisallowInterceptTouchEvent(false)
    }
    return if (!isRotationEnable) super.onTouchEvent(event) else mDetector!!.onTouchEvent(event)
  }

  private inner class GestureListener : SimpleOnGestureListener() {
    override fun onDown(e: MotionEvent): Boolean {
      if (!mScroller!!.isFinished) {
        mScroller!!.forceFinished(true)
      }
      return true
    }

    override fun onFling(
        e1: MotionEvent,
        e2: MotionEvent,
        velocityX: Float,
        velocityY: Float
    ): Boolean {
      if (abs(velocityX) > abs(velocityY)) {
        mFlingPoint = e2.x
        mScroller!!.fling(
            e2.x.toInt(),
            0,
            velocityX.toInt(),
            0,
            (-mPerimeter + e2.x).toInt(),
            (mPerimeter + e2.x).toInt(),
            0,
            0)
      } else if (abs(velocityY) > abs(velocityX)) {
        mFlingPoint = e2.y
        mScroller!!.fling(
            0,
            e2.y.toInt(),
            0,
            velocityY.toInt(),
            0,
            0,
            (-mPerimeter + e2.y).toInt(),
            (mPerimeter + e2.y).toInt())
      }
      invalidate()
      return super.onFling(e1, e2, velocityX, velocityY)
    }

    override fun onScroll(
        e1: MotionEvent,
        e2: MotionEvent,
        distanceX: Float,
        distanceY: Float
    ): Boolean {
      var rotate = mRotateAngle
      val dis =
          RotateUtil.getRotateAngle(
              PointF(e2.x - distanceX, e2.y - distanceY), PointF(e2.x, e2.y), mPointCenter)
      rotate += dis
      handleRotate(rotate)
      mRotateOrientation = dis
      return super.onScroll(e1, e2, distanceX, distanceY)
    }
  }

  override fun computeScroll() {
    if (mScroller!!.computeScrollOffset()) {
      val x = mScroller!!.currX
      val y = mScroller!!.currY
      val max = max(abs(x), abs(y))
      val rotateDis = RotateUtil.CIRCLE_ANGLE * (abs(max - mFlingPoint) / mPerimeter)
      var rotate = mRotateAngle
      if (mRotateOrientation > 0) {
        rotate += rotateDis
      } else if (mRotateOrientation < 0) {
        rotate -= rotateDis
      }
      handleRotate(rotate)
      mFlingPoint = max.toFloat()
      invalidate()
    }
  }

  private fun handleRotate(rotate: Double) {
    val mRotate = RotateUtil.getNormalizedAngle(rotate)
    mRotateAngle = mRotate
    invalidate()
  }

  override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
    super.onSizeChanged(w, h, oldw, oldh)
    mPointCenter = PointF((w / 2).toFloat(), (h / 2).toFloat())
  }

  private fun dp2px(dpValue: Float): Float {
    val scale = mContext.resources.displayMetrics.density
    return dpValue * scale + 0.5f
  }

  companion object {
    const val WEB_MODE_POLYGON = 1
    const val WEB_MODE_CIRCLE = 2
    const val VERTEX_ICON_POSITION_LEFT = 1
    const val VERTEX_ICON_POSITION_RIGHT = 2
    const val VERTEX_ICON_POSITION_TOP = 3
    const val VERTEX_ICON_POSITION_BOTTOM = 4
    const val VERTEX_ICON_POSITION_CENTER = 5
  }

  init {
    initAttrs(attrs)
    init()
  }
}
